package cn.maihe.elg.operation.centers.guogu.handler;

import cn.maihe.elg.operation.centers.guogu.auth.GuoGuCenterAuthConfig;
import cn.maihe.elg.operation.centers.guogu.auth.GuoGuHeaderInfo;
import cn.maihe.elg.operation.centers.guogu.dto.GuoGuBaseRespDTO;
import cn.maihe.elg.operation.centers.guogu.enums.GuoGuRespCodeEnum;
import cn.maihe.elg.operation.centers.guogu.exception.GuoGuException;
import cn.maihe.elg.operation.centers.supports.annotation.CenterTradeService;
import cn.maihe.elg.operation.model.enums.CenterNoEnum;
import cn.maihe.elg.operation.model.enums.CenterProviderEnum;
import cn.maihe.elg.operation.utils.ElgLogger;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description
 * @Author SSX
 * @Date 2025/03/18
 */
@RestController
@RequestMapping(value = "/v1/center")
@Slf4j
public class GuoGuCenterHandler {
    /**
     * 中心服务商
     */
    public static final CenterProviderEnum centerProvider = CenterProviderEnum.GUOGU;
    /**
     * 能够使用与该中心服务商的 中心信息
     */
    public static final List<String> enableCenterNos = Lists.newArrayList(CenterNoEnum.GUOGU.getCenterNo());
    /**
     * 中心服务商的接口实现类
     */
    private final Map<String, GuoGuCenterTradeService> tradeServiceMap = new HashMap<>();

    public GuoGuCenterHandler(@SuppressWarnings("rawtypes") final Collection<GuoGuCenterTradeService> baseCenterServices) {
        super();
        baseCenterServices.forEach(item -> {
            CenterTradeService ts = AnnotationUtils.findAnnotation(item.getClass(), CenterTradeService.class);
            if (centerProvider == ts.provider() && enableCenterNos.contains(ts.centerNo().getCenterNo())) {
                tradeServiceMap.put(ts.centerNo().getCenterNo() + ts.tradeType().name().toLowerCase(), item);
            }
        });
    }

    @PostMapping(value = "/guogu/{centerNo}/{orgCode}", consumes = {"application/json", "application/xml", "text/plain"})
    public @ResponseBody
    DeferredResult<Object> service(@PathVariable("centerNo") String centerNo, @PathVariable("orgCode") String orgCode, @RequestHeader(required = false) Map<String, Object> headerMap, @RequestBody final String encryptReqBody, final HttpServletRequest req, final HttpServletResponse resp) {
        return this.doService(centerNo, orgCode, (String) headerMap.get("method"), req, resp, headerMap, encryptReqBody);
    }

    protected DeferredResult<Object> doService(String centerNo, String orgCode, String tradeType, final HttpServletRequest req, final HttpServletResponse resp, final Map<String, Object> headerMap, final String encryptReqBody) {
        log.info("请求头部参数:{}", JSON.toJSONString(headerMap));
        log.info("请求报文参数[明文加密字符串]:{}", encryptReqBody);

        DeferredResult<Object> dr = new DeferredResult<Object>();
        if (!this.tradeServiceMap.containsKey(centerNo + tradeType.toLowerCase())) {
            dr.setResult(GuoGuBaseRespDTO.error("不支持的交易类型"));
            return dr;
        }

        CenterNoEnum centerNoEnum;
        try {
            centerNoEnum = CenterNoEnum.resolve(centerNo);
        } catch (Exception e) {
            log.error("暂不支持的交易中心[{}]:{}", centerNo, e.getMessage(), e);
            dr.setResult(GuoGuBaseRespDTO.error("暂不支持的交易中心[" + centerNo + "]"));
            return dr;
        }

        GuoGuCenterTradeService guoGuCenterTradeService = this.tradeServiceMap.get(centerNo + tradeType.toLowerCase());
        GuoGuCenterAuthConfig authConfig = guoGuCenterTradeService.getAuthConfig(centerNoEnum);

        // 业务数据先base64解码后再sm2解密
        String clearBizReqJsonBody = "";
        try {
            clearBizReqJsonBody = authConfig.getGuoGuEncryption().decrypt(encryptReqBody);
            String finalClearBizReqJsonBody = clearBizReqJsonBody;
            ElgLogger.info(log, log -> log.info("解密完请求报文:{}", finalClearBizReqJsonBody));
        } catch (Exception e) {
            log.error("报文解密失败[{}]:{}", centerNo, e.getMessage(), e);
            dr.setResult(GuoGuBaseRespDTO.error("报文解密失败[" + centerNo + "]"));
            return dr;
        }

        // 封装请求头
        GuoGuHeaderInfo headerInfo;
        try {
            headerInfo = GuoGuHeaderInfo.of(headerMap);
        } catch (Exception e) {
            log.error("请求头参数错误[{}]:{}", centerNo, e.getMessage(), e);
            dr.setResult(GuoGuBaseRespDTO.error("请求头参数错误[" + e.getMessage() + "]"));
            return dr;
        }

        String[] authorization = new String(Base64.decodeBase64(headerInfo.getAuthorization().split(" ")[1])).split(":");
        log.info("中心：{},交易类型：{},authorization：{}", centerNoEnum.getCenterName(), tradeType, authorization);
        String clientId = authorization[0];
        try {
            // SM3验签
            boolean verifySignature;
            try {
                verifySignature = authConfig.getGuoGuAuthorization().verifySignature(clientId, clearBizReqJsonBody, headerInfo.getSignature());
            } catch (Exception e) {
                throw GuoGuException.error("验签失败:" + e.getMessage(), e);
            }

            if (!verifySignature) {
                throw GuoGuException.of(GuoGuRespCodeEnum.FAILURE, "验签失败");
            }
        } catch (Exception e) {
            log.error("验签异常[{}]:{}", centerNo, e.getMessage(), e);
            dr.setResult(GuoGuBaseRespDTO.error("验签异常[" + e.getMessage() + "]"));
            return dr;
        }

        Map<String, Object> params = JSON.parseObject(clearBizReqJsonBody, Map.class);

        Map<String, Object> attrMap = new HashMap<>();
        attrMap.put("clientId", clientId);

        GuoGuBaseRespDTO respDTO;
        try {
            respDTO = guoGuCenterTradeService.doService(centerNoEnum, orgCode, params, attrMap);
        } catch (Exception e) {
            log.error("中心：{},交易类型：{},服务错误：{}", centerNoEnum.getCenterName(), tradeType, e.getMessage(), e);
            respDTO = GuoGuBaseRespDTO.error("系统错误");
        }

        log.info("中心：{},交易类型：{},响应报文(明文)：{}", centerNoEnum.getCenterName(), tradeType, JSON.toJSONString(respDTO));
        dr.setResult(authConfig.getGuoGuEncryption().encryptForGuoGu(clientId, JSON.toJSONString(respDTO)));
        log.info("中心：{},交易类型：{},响应报文(密文)：{}", centerNoEnum.getCenterName(), tradeType, JSON.toJSONString(dr.getResult()));
        return dr;
    }
}
